#region <<版权版本注释>>

// ----------------------------------------------------------------
// Copyright ©2021-Present ZhaiFanhua All Rights Reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
// FileName:MenuService
// Guid:6c2b3c4d-5e6f-7890-abcd-ef12345678bb
// Author:zhaifanhua
// Email:me@zhaifanhua.com
// CreateTime:2025/10/31 7:05:00
// ----------------------------------------------------------------

#endregion <<版权版本注释>>

using XiHan.BasicApp.Rbac.Constants;
using XiHan.BasicApp.Rbac.Dtos.Menus;
using XiHan.BasicApp.Rbac.Entities;
using XiHan.BasicApp.Rbac.Extensions;
using XiHan.BasicApp.Rbac.Managers;
using XiHan.BasicApp.Rbac.Repositories.Abstractions;
using XiHan.BasicApp.Rbac.Services.Abstractions;
using XiHan.Framework.Application.Services;

namespace XiHan.BasicApp.Rbac.Services.Implementations;

/// <summary>
/// 菜单服务实现
/// </summary>
public class MenuService : CrudApplicationServiceBase<SysMenu, MenuDto, RbacIdType, CreateMenuDto, UpdateMenuDto>, IMenuService
{
    private readonly IMenuRepository _menuRepository;
    private readonly MenuManager _menuManager;

    /// <summary>
    /// 构造函数
    /// </summary>
    public MenuService(
        IMenuRepository menuRepository,
        MenuManager menuManager) : base(menuRepository)
    {
        _menuRepository = menuRepository;
        _menuManager = menuManager;
    }

    #region 重写基类方法

    /// <summary>
    /// 创建菜单
    /// </summary>
    public override async Task<MenuDto> CreateAsync(CreateMenuDto input)
    {
        // 验证菜单编码唯一性
        if (!await _menuManager.IsMenuCodeUniqueAsync(input.MenuCode))
        {
            throw new InvalidOperationException(ErrorMessageConstants.MenuCodeExists);
        }

        var menu = new SysMenu
        {
            ParentId = input.ParentId,
            MenuName = input.MenuName,
            MenuCode = input.MenuCode,
            MenuType = input.MenuType,
            Path = input.Path,
            Component = input.Component,
            Icon = input.Icon,
            Permission = input.Permission,
            IsExternal = input.IsExternal,
            IsCache = input.IsCache,
            IsVisible = input.IsVisible,
            Sort = input.Sort,
            Remark = input.Remark
        };

        await _menuRepository.AddAsync(menu);

        return menu.ToDto();
    }

    /// <summary>
    /// 更新菜单
    /// </summary>
    public override async Task<MenuDto> UpdateAsync(RbacIdType id, UpdateMenuDto input)
    {
        var menu = await _menuRepository.GetByIdAsync(id) ??
            throw new InvalidOperationException(ErrorMessageConstants.MenuNotFound);

        // 更新菜单信息
        if (input.ParentId.HasValue)
        {
            menu.ParentId = input.ParentId;
        }

        if (input.MenuName != null)
        {
            menu.MenuName = input.MenuName;
        }

        if (input.MenuType.HasValue)
        {
            menu.MenuType = input.MenuType.Value;
        }

        if (input.Path != null)
        {
            menu.Path = input.Path;
        }

        if (input.Component != null)
        {
            menu.Component = input.Component;
        }

        if (input.Icon != null)
        {
            menu.Icon = input.Icon;
        }

        if (input.Permission != null)
        {
            menu.Permission = input.Permission;
        }

        if (input.IsExternal.HasValue)
        {
            menu.IsExternal = input.IsExternal.Value;
        }

        if (input.IsCache.HasValue)
        {
            menu.IsCache = input.IsCache.Value;
        }

        if (input.IsVisible.HasValue)
        {
            menu.IsVisible = input.IsVisible.Value;
        }

        if (input.Status.HasValue)
        {
            menu.Status = input.Status.Value;
        }

        if (input.Sort.HasValue)
        {
            menu.Sort = input.Sort.Value;
        }

        if (input.Remark != null)
        {
            menu.Remark = input.Remark;
        }

        await _menuRepository.UpdateAsync(menu);

        return menu.ToDto();
    }

    /// <summary>
    /// 删除菜单
    /// </summary>
    public override async Task<bool> DeleteAsync(RbacIdType id)
    {
        var menu = await _menuRepository.GetByIdAsync(id) ??
            throw new InvalidOperationException(ErrorMessageConstants.MenuNotFound);

        // 检查是否可以删除
        if (!await _menuManager.CanDeleteAsync(id))
        {
            throw new InvalidOperationException(ErrorMessageConstants.MenuHasChildren);
        }

        return await _menuRepository.DeleteAsync(menu);
    }

    #endregion 重写基类方法

    #region 业务特定方法

    /// <summary>
    /// 根据菜单编码获取菜单
    /// </summary>
    public async Task<MenuDto?> GetByMenuCodeAsync(string menuCode)
    {
        var menu = await _menuRepository.GetByMenuCodeAsync(menuCode);
        return menu?.ToDto();
    }

    /// <summary>
    /// 获取菜单树
    /// </summary>
    public async Task<List<MenuTreeDto>> GetTreeAsync()
    {
        var allMenus = await _menuRepository.GetListAsync();
        var menuDtos = allMenus.ToDto();
        return menuDtos.BuildTree();
    }

    /// <summary>
    /// 根据父级ID获取子菜单
    /// </summary>
    public async Task<List<MenuDto>> GetChildrenAsync(RbacIdType parentId)
    {
        var children = await _menuRepository.GetChildrenAsync(parentId);
        return children.ToDto();
    }

    /// <summary>
    /// 获取角色的菜单列表
    /// </summary>
    public async Task<List<MenuDto>> GetByRoleIdAsync(RbacIdType roleId)
    {
        var menus = await _menuRepository.GetByRoleIdAsync(roleId);
        return menus.ToDto();
    }

    /// <summary>
    /// 获取用户的菜单树
    /// </summary>
    public async Task<List<MenuTreeDto>> GetUserMenuTreeAsync(RbacIdType userId)
    {
        var menus = await _menuRepository.GetByUserIdAsync(userId);
        var menuDtos = menus.ToDto();
        return menuDtos.BuildTree();
    }

    #endregion 业务特定方法

    #region 映射方法实现

    /// <summary>
    /// 映射实体到DTO
    /// </summary>
    protected override Task<MenuDto> MapToEntityDtoAsync(SysMenu entity)
    {
        return Task.FromResult(entity.ToDto());
    }

    /// <summary>
    /// 映射 MenuDto 到实体（基类方法）
    /// </summary>
    protected override Task<SysMenu> MapToEntityAsync(MenuDto dto)
    {
        var entity = new SysMenu
        {
            ParentId = dto.ParentId,
            MenuName = dto.MenuName,
            MenuCode = dto.MenuCode,
            MenuType = dto.MenuType,
            Path = dto.Path,
            Component = dto.Component,
            Icon = dto.Icon,
            Permission = dto.Permission,
            IsExternal = dto.IsExternal,
            IsCache = dto.IsCache,
            IsVisible = dto.IsVisible,
            Status = dto.Status,
            Sort = dto.Sort,
            Remark = dto.Remark
        };

        return Task.FromResult(entity);
    }

    /// <summary>
    /// 映射 MenuDto 到现有实体（基类方法）
    /// </summary>
    protected override Task MapToEntityAsync(MenuDto dto, SysMenu entity)
    {
        entity.ParentId = dto.ParentId;
        if (dto.MenuName != null) entity.MenuName = dto.MenuName;
        entity.MenuType = dto.MenuType;
        if (dto.Path != null) entity.Path = dto.Path;
        if (dto.Component != null) entity.Component = dto.Component;
        if (dto.Icon != null) entity.Icon = dto.Icon;
        if (dto.Permission != null) entity.Permission = dto.Permission;
        entity.IsExternal = dto.IsExternal;
        entity.IsCache = dto.IsCache;
        entity.IsVisible = dto.IsVisible;
        entity.Status = dto.Status;
        entity.Sort = dto.Sort;
        if (dto.Remark != null) entity.Remark = dto.Remark;

        return Task.CompletedTask;
    }

    /// <summary>
    /// 映射创建DTO到实体
    /// </summary>
    protected override Task<SysMenu> MapToEntityAsync(CreateMenuDto createDto)
    {
        var entity = new SysMenu
        {
            ParentId = createDto.ParentId,
            MenuName = createDto.MenuName,
            MenuCode = createDto.MenuCode,
            MenuType = createDto.MenuType,
            Path = createDto.Path,
            Component = createDto.Component,
            Icon = createDto.Icon,
            Permission = createDto.Permission,
            IsExternal = createDto.IsExternal,
            IsCache = createDto.IsCache,
            IsVisible = createDto.IsVisible,
            Sort = createDto.Sort,
            Remark = createDto.Remark
        };

        return Task.FromResult(entity);
    }

    /// <summary>
    /// 映射更新DTO到现有实体
    /// </summary>
    protected override Task MapToEntityAsync(UpdateMenuDto updateDto, SysMenu entity)
    {
        if (updateDto.ParentId.HasValue) entity.ParentId = updateDto.ParentId;
        if (updateDto.MenuName != null) entity.MenuName = updateDto.MenuName;
        if (updateDto.MenuType.HasValue) entity.MenuType = updateDto.MenuType.Value;
        if (updateDto.Path != null) entity.Path = updateDto.Path;
        if (updateDto.Component != null) entity.Component = updateDto.Component;
        if (updateDto.Icon != null) entity.Icon = updateDto.Icon;
        if (updateDto.Permission != null) entity.Permission = updateDto.Permission;
        if (updateDto.IsExternal.HasValue) entity.IsExternal = updateDto.IsExternal.Value;
        if (updateDto.IsCache.HasValue) entity.IsCache = updateDto.IsCache.Value;
        if (updateDto.IsVisible.HasValue) entity.IsVisible = updateDto.IsVisible.Value;
        if (updateDto.Status.HasValue) entity.Status = updateDto.Status.Value;
        if (updateDto.Sort.HasValue) entity.Sort = updateDto.Sort.Value;
        if (updateDto.Remark != null) entity.Remark = updateDto.Remark;

        return Task.CompletedTask;
    }

    #endregion 映射方法实现
}
